home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Music / EDIT / AmiSOX3.3 / dist / 8svx.c < prev    next >
C/C++ Source or Header  |  1995-08-23  |  8KB  |  328 lines

  1. /*
  2.  * Amiga 8SVX format handler: W V Neisius, February 1992
  3.  */
  4.  
  5. #if    defined(unix) || defined(__OS2__)
  6. #include <sys/types.h>
  7. #endif
  8. #include <math.h>
  9. #include <errno.h>
  10. #ifdef    VMS
  11. #include <perror.h>
  12. #endif
  13. #include "st.h"
  14.  
  15. /* Private data used by writer */
  16. struct svxpriv {
  17.         unsigned long nsamples;
  18.     FILE *ch[4];
  19. };
  20.  
  21. #ifndef SEEK_CUR
  22. #define SEEK_CUR        1
  23. #endif
  24. #ifndef SEEK_SET
  25. #define SEEK_SET        0
  26. #endif
  27.  
  28. /*======================================================================*/
  29. /*                         8SVXSTARTREAD                                */
  30. /*======================================================================*/
  31.  
  32. svxstartread(ft)
  33. ft_t ft;
  34. {
  35.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  36.  
  37.     char buf[12];
  38.     char *endptr;
  39.     char *chunk_buf;
  40.  
  41.     unsigned long totalsize;
  42.     unsigned long chunksize;
  43.  
  44.     int channels;
  45.     long rate;
  46.     int littlendian = 0;
  47.     int i;
  48.  
  49.     unsigned long chan1_pos;
  50.  
  51.     rate = 0;
  52.     channels = 1;
  53.  
  54.     /* read FORM chunk */
  55.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "FORM", 4) != 0)
  56.         fail("8SVX: header does not begin with magic word 'FORM'");
  57.     totalsize = rblong(ft);
  58.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "8SVX", 4) != 0)
  59.         fail("8SVX: 'FORM' chunk does not specify '8SVX' as type");
  60.  
  61.     /* read chunks until 'BODY' (or end) */
  62.     while (fread(buf,1,4,ft->fp) == 4 && strncmp(buf,"BODY",4) != 0) {
  63.         if (strncmp(buf,"VHDR",4) == 0) {
  64.             chunksize = rblong(ft);
  65.             if (chunksize != 20)
  66.                 fail ("8SVX: VHDR chunk has bad size");
  67.             fseek(ft->fp,12,SEEK_CUR);
  68.             rate = rbshort(ft);
  69.             fseek(ft->fp,1,SEEK_CUR);
  70.             fread(buf,1,1,ft->fp);
  71.             if (buf[0] != 0)
  72.                 fail ("8SVX: unsupported data compression");
  73.             fseek(ft->fp,4,SEEK_CUR);
  74.             continue;
  75.         }
  76.  
  77.         if (strncmp(buf,"ANNO",4) == 0) {
  78.             chunksize = rblong(ft);
  79.             if (chunksize & 1)
  80.                 chunksize++;
  81.             chunk_buf = (char *) malloc(chunksize + 1);
  82.             if (fread(chunk_buf,1,(size_t)chunksize,ft->fp) 
  83.                     != chunksize)
  84.                 fail("8SVX: Unexpected EOF in ANNO header");
  85.             chunk_buf[chunksize] = '\0';
  86.             report ("%s",chunk_buf);
  87.             free(chunk_buf);
  88.  
  89.             continue;
  90.         }
  91.  
  92.         if (strncmp(buf,"NAME",4) == 0) {
  93.             chunksize = rblong(ft);
  94.             if (chunksize & 1)
  95.                 chunksize++;
  96.             chunk_buf = (char *) malloc(chunksize + 1);
  97.             if (fread (chunk_buf,1,(size_t)chunksize,ft->fp) 
  98.                     != chunksize)
  99.                 fail("8SVX: Unexpected EOF in NAME header");
  100.             chunk_buf[chunksize] = '\0';
  101.             report ("%s",chunk_buf);
  102.             free(chunk_buf);
  103.  
  104.             continue;
  105.         }
  106.  
  107.         if (strncmp(buf,"CHAN",4) == 0) {
  108.             chunksize = rblong(ft);
  109.             if (chunksize != 4) 
  110.                 fail("8SVX: Short channel chunk");
  111.             channels = rblong(ft);
  112.             channels = (channels & 0x01) + 
  113.                     ((channels & 0x02) >> 1) +
  114.                        ((channels & 0x04) >> 2) + 
  115.                     ((channels & 0x08) >> 3);
  116.  
  117.             continue;
  118.         }
  119.  
  120.         /* some other kind of chunk */
  121.         chunksize = rblong(ft);
  122.         if (chunksize & 1)
  123.             chunksize++;
  124.         fseek(ft->fp,chunksize,SEEK_CUR);
  125.         continue;
  126.  
  127.     }
  128.  
  129.     if (rate == 0)
  130.         fail ("8SVX: invalid rate");
  131.     if (strncmp(buf,"BODY",4) != 0)
  132.         fail ("8SVX: BODY chunk not found");
  133.     p->nsamples = rblong(ft);
  134.  
  135.     ft->info.channels = channels;
  136.     ft->info.rate = rate;
  137.     ft->info.style = SIGN2;
  138.     ft->info.size = BYTE;
  139.  
  140.     /* open files to channels */
  141.     p->ch[0] = ft->fp;
  142.     chan1_pos = ftell(p->ch[0]);
  143.  
  144.     for (i = 1; i < channels; i++) {
  145.         if ((p->ch[i] = fopen(ft->filename, READBINARY)) == NULL)
  146.             fail("Can't open channel file '%s': %s",
  147.                 ft->filename, strerror(errno));
  148.  
  149.         /* position channel files */
  150.         if (fseek(p->ch[i],chan1_pos,SEEK_SET))
  151.             fail ("Can't position channel %d: %s",i,strerror(errno));
  152.         if (fseek(p->ch[i],p->nsamples/channels*i,SEEK_CUR))
  153.             fail ("Can't seek channel %d: %s",i,strerror(errno));
  154.     }
  155.  
  156.  
  157.     endptr = (char *) &littlendian;
  158.     *endptr = 1;
  159.     if (littlendian == 1)
  160.         ft->swap = 1;
  161.  
  162. }
  163.  
  164. /*======================================================================*/
  165. /*                         8SVXREAD                                     */
  166. /*======================================================================*/
  167. svxread(ft, buf, nsamp) 
  168. ft_t ft;
  169. long *buf, nsamp;
  170. {
  171.     register unsigned long datum;
  172.     int done = 0;
  173.     int i;
  174.  
  175.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  176.  
  177.     while (done < nsamp) {
  178.         for (i = 0; i < ft->info.channels; i++) {
  179.             datum = getc(p->ch[i]);
  180.             if (feof(p->ch[i]))
  181.                 return done;
  182.             /* scale signed up to long's range */
  183.             *buf++ = LEFT(datum, 24);
  184.         }
  185.         done += ft->info.channels;
  186.     }
  187.     return done;
  188. }
  189.  
  190. /*======================================================================*/
  191. /*                         8SVXSTOPREAD                                 */
  192. /*======================================================================*/
  193. svxstopread(ft)
  194. ft_t ft;
  195. {
  196.     int i;
  197.  
  198.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  199.  
  200.     /* close channel files */
  201.     for (i = 1; i < ft->info.channels; i++) {
  202.         fclose (p->ch[i]);
  203.     }
  204. }
  205.  
  206. /*======================================================================*/
  207. /*                         8SVXSTARTWRITE                               */
  208. /*======================================================================*/
  209. svxstartwrite(ft)
  210. ft_t ft;
  211. {
  212.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  213.     int littlendian = 0;
  214.     int i;
  215.     char *endptr;
  216.  
  217.     /* open channel output files */
  218.     p->ch[0] = ft->fp;
  219.     for (i = 1; i < ft->info.channels; i++) {
  220.         if ((p->ch[i] = tmpfile()) == NULL)
  221.             fail("Can't open channel output file: %s",
  222.                 strerror(errno));
  223.     }
  224.  
  225.     /* write header (channel 0) */
  226.     ft->info.style = SIGN2;
  227.     ft->info.size = BYTE;
  228.  
  229.     p->nsamples = 0;
  230.     svxwriteheader(ft, p->nsamples);
  231.  
  232.     endptr = (char *) &littlendian;
  233.     *endptr = 1;
  234.     if (littlendian == 1)
  235.         ft->swap = 1;
  236. }
  237.  
  238. /*======================================================================*/
  239. /*                         8SVXWRITE                                    */
  240. /*======================================================================*/
  241.  
  242. svxwrite(ft, buf, len)
  243. ft_t ft;
  244. long *buf, len;
  245. {
  246.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  247.  
  248.     register long datum;
  249.     int done = 0;
  250.     int i;
  251.  
  252.     p->nsamples += len;
  253.  
  254.     while(done < len) {
  255.         for (i = 0; i < ft->info.channels; i++) {
  256.             datum = RIGHT(*buf++, 24);
  257.             putc((int)datum, p->ch[i]);
  258.         }
  259.         done += ft->info.channels;
  260.     }
  261. }
  262.  
  263. /*======================================================================*/
  264. /*                         8SVXSTOPWRITE                                */
  265. /*======================================================================*/
  266.  
  267. svxstopwrite(ft)
  268. ft_t ft;
  269. {
  270.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  271.  
  272.     int i;
  273.     int len;
  274.     char svxbuf[512];
  275.  
  276.     /* append all channel pieces to channel 0 */
  277.     /* close temp files */
  278.     for (i = 1; i < ft->info.channels; i++) {
  279.         if (fseek (p->ch[i], 0L, 0))
  280.             fail ("Can't rewind channel output file %d",i);
  281.         while (!feof(p->ch[i])) {
  282.             len = fread (svxbuf, 1, 512, p->ch[i]);
  283.             fwrite (svxbuf, 1, len, p->ch[0]);
  284.         }
  285.         fclose (p->ch[i]);
  286.     }
  287.  
  288.     /* fixup file sizes in header */
  289.     if (fseek(ft->fp, 0L, 0) != 0)
  290.         fail("can't rewind output file to rewrite 8SVX header");
  291.     svxwriteheader(ft, p->nsamples);
  292. }
  293.  
  294. /*======================================================================*/
  295. /*                         8SVXWRITEHEADER                              */
  296. /*======================================================================*/
  297. #define SVXHEADERSIZE 100
  298. svxwriteheader(ft,nsamples)
  299. ft_t ft;
  300. long nsamples;
  301. {
  302.     fputs ("FORM", ft->fp);
  303.     wblong(ft, nsamples + SVXHEADERSIZE - 8);  /* size of file */
  304.     fputs("8SVX", ft->fp); /* File type */
  305.  
  306.     fputs ("VHDR", ft->fp);
  307.     wblong(ft, (long) 20); /* number of bytes to follow */
  308.     wblong(ft, nsamples);  /* samples, 1-shot */
  309.     wblong(ft, (long) 0);  /* samples, repeat */
  310.     wblong(ft, (long) 0);  /* samples per repeat cycle */
  311.     wbshort(ft, (int) ft->info.rate); /* samples per second */
  312.     fputc(1,ft->fp); /* number of octaves */
  313.     fputc(0,ft->fp); /* data compression (none) */
  314.     wbshort(ft,1); wbshort(ft,0); /* volume */
  315.  
  316.     fputs ("ANNO", ft->fp);
  317.     wblong(ft, (long) 32); /* length of block */
  318.     fputs ("File created by Sound Exchange  ", ft->fp);
  319.  
  320.     fputs ("CHAN", ft->fp);
  321.     wblong(ft, (long) 4);
  322.     wblong(ft, (ft->info.channels == 2) ? (long) 6 :
  323.            (ft->info.channels == 4) ? (long) 15 : (long) 2);
  324.  
  325.     fputs ("BODY", ft->fp);
  326.     wblong(ft, nsamples); /* samples in file */
  327. }
  328.